#include "stdafx.h"
#include "orderlink.h"
#include "config.h"
#include "LogFile.h"

#include <sstream>


OrderLink::OrderLink(void) {
	mLinkOk = false;
	mDialog = 0;
	mPersistFile = 0;
}


OrderLink::~OrderLink(void) {
	if( mPersistFile ){
		mPersistFile->Close();
	}
}

bool OrderLink::LoadPersist() {
	Config *cfg = Config::getInstance();
	string persistFile = cfg->getValue("OrderPersistFile", "OrderPesist.txt");
	PersistFile::LoadPersistFile(persistFile, OrderLink::ProcPersistedLine, this);
	mPersistFile = new PersistFile();
	mPersistFile->Open(persistFile);

	return true;
}

void OrderLink::ProcPersistedLine(const string & line, void *ctx) {
	OrderLink *link = (OrderLink *) (ctx);
	link->procPersistedLine(line);
}

void OrderLink::managerOrder(AdaptorOrder *adaptorOrder) {
	ZAdaptorOrderMessage *order = &adaptorOrder->mOrder, *origOrder;
	ZAdaptorOrderStatusMessage *status = &adaptorOrder->mStatus, *origStatusMsg;
	ZAdaptorOrderStatusField::Status origStatus;
	AdaptorOrder *origAdaptorOrder;
	int orderID;
	int action = order->zOrderActionField.zVal;
	if ( action == ZAdaptorOrderActionField::Insert ) {
		 orderID = order->zOrderIDField.zVal;
		 if( lookupOrder(orderID) ) {
			 internalReject(adaptorOrder, ZAdaptorErrorCodeField::DuplicateOrderID);
			 stringstream ss;
			 ss << "Duplicated order id. the order is rejected by adaptor (" << orderID << ")";
			 LogFile::PrintLine(ss.str());
			 recycleOrder(adaptorOrder);
		 } else if ( sendOrder(adaptorOrder) ) {
			mOrderMap.insert( IDOrderPair(order->zOrderIDField.zVal, adaptorOrder) );
			status->zOrderStatusField.zVal = ZAdaptorOrderStatusField::PendingInsert;
			status->zCurrentFilledSizeFiled.zVal = 0;
			status->zTotalFilledSizeField.zVal = 0;
			status->zSymbolField.zVal = order->zSymbolField.zVal;
			status->zOrderIDField.zVal = order->zOrderIDField.zVal;
			persistOrder(adaptorOrder);
		}
	} else if ( action == ZAdaptorOrderActionField::Update ||
		action == ZAdaptorOrderActionField::Cancel ) {
		orderID = order->zOrderIDField.zVal;
		origAdaptorOrder = lookupOrder(orderID);
		if(origAdaptorOrder == 0) {
			internalReject(adaptorOrder, ZAdaptorErrorCodeField::OriginalOrderNotFound);			
		} else {
			origOrder = &origAdaptorOrder->mOrder;
			origStatusMsg = &origAdaptorOrder->mStatus;
			origStatus = (ZAdaptorOrderStatusField::Status) origStatusMsg->zOrderStatusField.zVal;
			switch(origStatus) {
			case ZAdaptorOrderStatusField::PendingFill:
			case ZAdaptorOrderStatusField::PartialFill:
				if (action == ZAdaptorOrderActionField::Update && cancelOrder(origAdaptorOrder, false)) {
					origStatusMsg->zOrderStatusField.zVal = ZAdaptorOrderStatusField::PendingUpdate;
				} else if (action == ZAdaptorOrderActionField::Cancel && cancelOrder(origAdaptorOrder, true)) {
					origStatusMsg->zOrderStatusField.zVal = ZAdaptorOrderStatusField::PendingCancel;
				}
				break;
			case ZAdaptorOrderStatusField::PendingCancel:
				internalReject(adaptorOrder, ZAdaptorErrorCodeField::WaitForCancelAck);
				break;
			case ZAdaptorOrderStatusField::PendingUpdate:
				internalReject(adaptorOrder, ZAdaptorErrorCodeField::WaitForUpdateAck);
				break;
			case ZAdaptorOrderStatusField::PendingInsert:
				internalReject(adaptorOrder, ZAdaptorErrorCodeField::WaitForInsertAck);
				break;
			case ZAdaptorOrderStatusField::Filled:
			case ZAdaptorOrderStatusField::Canceled:
				internalReject(adaptorOrder, ZAdaptorErrorCodeField::OrderCanceledOrFilled);
				break;
			default: break;
			}
		}
		recycleOrder(adaptorOrder);
	}
}

AdaptorOrder * OrderLink::lookupOrder(int orderID) {
	map<int, AdaptorOrder *>::iterator it = mOrderMap.find( orderID );
	if ( it == mOrderMap.end() ) {
		return 0;
	} else {
		return it->second;
	}
}

void OrderLink::internalReject(AdaptorOrder *order, ZAdaptorErrorCodeField::ErrorCode code) {
	ZAdaptorOrderStatusMessage msg;
	ZAdaptorOrderMessage *orderMsg = &order->mOrder;
	msg.zOrderIDField.zVal = orderMsg->zOrderIDField.zVal;
	msg.zSymbolField.zVal = orderMsg->zSymbolField.zVal;
	msg.zErrorCodeField.zVal = code;
	msg.zOrderTextField.zVal = ZAdaptorErrorCodeField::ErrorMessage(code);
	char buf[ZAdaptorOrderStatusMessage::Length+1];
	int len = ZAdaptorOrderStatusMessage::set(buf, &msg);
	order->mSocket->Send(buf, len);
}

void OrderLink::OnOrderAccepted(int orderID) {
	AdaptorOrder *order = lookupOrder(orderID);
	if( order == 0) return;

	ZAdaptorOrderStatusMessage *status = &order->mStatus;
	if( status->zOrderStatusField.zVal == ZAdaptorOrderStatusField::PendingInsert)
		status->zOrderStatusField.zVal = ZAdaptorOrderStatusField::PendingFill;

	status->zCurrentFilledSizeFiled.zVal = 0;
	status->zOrderTextField.zVal = "order accepted";

	char buf[ZAdaptorOrderStatusMessage::Length];
	int len = ZAdaptorOrderStatusMessage::set(buf, status);
	order->mSocket->Send(buf, len, 0);
}

void OrderLink::OnOrderClosed(int orderID) {
	AdaptorOrder *order = lookupOrder(orderID);
	if( order == 0) return;

	ZAdaptorOrderStatusMessage *status = &order->mStatus;

	status->zOrderStatusField.zVal = ZAdaptorOrderStatusField::Canceled;
	status->zOrderTextField.zVal = "order closed";

	status->zCurrentFilledSizeFiled.zVal = 0;

	char buf[ZAdaptorOrderStatusMessage::Length];
	int len = ZAdaptorOrderStatusMessage::set(buf, status);
	order->mSocket->Send(buf, len, 0);
}

void OrderLink::OnOrderTraded(int orderID, double px, int sz) {
	AdaptorOrder *order = lookupOrder(orderID);
	if( order == 0) return;

	ZAdaptorOrderStatusMessage *status = &order->mStatus;

	status->zCurrentFilledSizeFiled.zVal = sz;
	status->zFilledPriceField.zVal = px;
	status->zTotalFilledSizeField.zVal += sz;
	status->zRemainSizeField.zVal -= sz;

	status->zOrderTextField.zVal = "order traded";

	if(status->zRemainSizeField.zVal == 0)
		status->zOrderStatusField.zVal = ZAdaptorOrderStatusField::Filled;
	else
		status->zOrderStatusField.zVal = ZAdaptorOrderStatusField::PartialFill;

	char buf[ZAdaptorOrderStatusMessage::Length];
	int len = ZAdaptorOrderStatusMessage::set(buf, status);
	order->mSocket->Send(buf, len, 0);
}

AdaptorOrder *OrderLink::getOrder() {
	if (mFreeOrderList.size() == 0) {
		static const int BatchOrderSize = 100;
		for(int i=0; i<BatchOrderSize; ++i) {
			mFreeOrderList.push_back(newOrder());
		}
	}
	AdaptorOrder *order = mFreeOrderList.front();
	mFreeOrderList.pop_front();

	return order;
}

void OrderLink::recycleOrder(AdaptorOrder *order) {
	mFreeOrderList.push_back(order);
}